package cn.ichiva.dl.tushare.job.handler;

import cn.ichiva.common.DataHelper;
import cn.ichiva.common.DateUtils;
import cn.ichiva.common.io.IOHelper;
import cn.ichiva.dl.tushare.analy.impl.Trade;
import cn.ichiva.dl.tushare.common.MailHelper;
import cn.ichiva.dl.tushare.job.TuShareEVN;
import cn.ichiva.tushare.sdk.tushare.entity.TuTable;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import org.bytedeco.javacv.FrameFilter;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import play.libs.F;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.*;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 预测任务
 *
 * 读取data目录下所有股票进行预测
 */
public class ForecastJobHandler extends IJobHandler {
	String rootDir = "./data";
	TuShareEVN evn = TuShareEVN.getInstance();

	@Override
	public ReturnT<String> execute(String param) throws Exception {
		String day = DateUtils.toString(new Date(), DateUtils.FORMAT_SMART_DD);
		Optional<TuTable> tuTable = evn.getTradeCal().get(day, day);
		if(!tuTable.isPresent()) XxlJobLogger.log("读取交易日历异常");
		String[][] items = tuTable.get().getItems();
		if("0".equals(items[0][2])) XxlJobLogger.log("休市,day = " + day);
		else {
			for (File file : new File(rootDir).listFiles()) {
				String name = file.getName();
				String suffix = name.substring(name.length() - 2);
				if ("SH".equalsIgnoreCase(suffix) || "SZ".equalsIgnoreCase(suffix)) forecast(file,day);
			}
		}

		return SUCCESS;
	}

	/**
	 * 写入预测值
	 *
	 * 1.使用历史预测值进行操作
	 * @param file
	 * @param day
	 */
	private void forecast(File file, String day) {
		String ts_code = file.getName();
		INDArray in = evn.getINDArray(ts_code,day);
		double price = in.getDouble(new int[]{0, 0, 0});
		File optFile = new File(file, "opt.txt");
		File tradeFile = new File(file, "trade.obj");

		/** 执行预测结果并删除预测结果 */
		if(optFile.exists()){
			try {
				byte[] bytes = IOHelper.read(optFile);
				String[] arr = new String(bytes, "utf-8").split("=");
				Trade trade;
				if(tradeFile.exists()){
					trade = (Trade) IOHelper.readObject(tradeFile);
				}else {
					trade = new Trade();
				}
				trade.opt(day,price,Integer.parseInt(arr[1]));

				IOHelper.write(tradeFile,DataHelper.toByte(trade));
				if (!optFile.delete()) {
					XxlJobLogger.log("%s 上一交易日预测结果删除失败",day);
				}
			}catch (IOException e){
				XxlJobLogger.log("%s IO异常",day);
			} catch (ClassNotFoundException e) {
				XxlJobLogger.log("%s 类型转换异常",day);
			}
		}else {
			XxlJobLogger.log(String.format("%s 上一交易日未作出预测",day));
		}

		try {
			MultiLayerNetwork network = (MultiLayerNetwork) IOHelper.readObject(new File(file, "network.obj"));
			INDArray output = network.rnnTimeStep(in);

			List<Double> list = Arrays.asList(output.getDouble(new long[]{0, 0,0}),
					output.getDouble(new long[]{0, 1,0}),
					output.getDouble(new long[]{0, 2,0}));
			double max = list.stream().mapToDouble(e -> e).max().getAsDouble();

			int opt;
			if(max == list.get(0)) opt = 1;
			else if(max == list.get(2)) opt = -1;
			else opt = 0;

			byte[] bytes = (day + "=" + opt).getBytes("utf-8");
			IOHelper.write(optFile, bytes);

			push(file,day,opt);
		} catch (IOException e) {
			XxlJobLogger.log("io异常",e);
		} catch (ClassNotFoundException e) {
			XxlJobLogger.log("反序列化异常",e);
		} catch (Exception e){
			XxlJobLogger.log("未知异常",e);
		}
	}

	/**
	 * 向订阅用户推送
	 * @param file
	 * @param day
	 * @param opt
	 */
	private void push(File file, String day, int opt) {
		String ts_name = file.getName();
		File mailFile = new File(file, "subscribe.txt");
		if(!mailFile.exists()){
			XxlJobLogger.log(ts_name + "没有订阅");
		}

		String prophesy = "观望";
		if(opt > 0) prophesy = "买入";
		else if(opt < 0) prophesy = "卖出";
		String text = String.format("%s 做出预测 %s => %s",day,ts_name,prophesy);
		String subject = ts_name + "" + prophesy;
		String from = "951513793@qq.com";
		Session session = MailHelper.getSession("951513793@qq.com", "xtbbkqjpzjjqbfea");
		try {
			List<String> mails = Files.readAllLines(mailFile.toPath());
			for (String mail : mails) {
				sendMail(session,from,mail,subject,text);
			}
		} catch (IOException e) {
			XxlJobLogger.log("读取订阅io异常",e);
		}
	}

	private void sendMail(Session session, String from,String to, String subject, String text) {
		try{
			MimeMessage message = new MimeMessage(session);
			message.setFrom(new InternetAddress(from));
			message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
			message.setSubject(subject);
			message.setText(text);
			Transport.send(message);

			XxlJobLogger.log("发送订阅邮件到::" + to);
		}catch (MessagingException e) {
			XxlJobLogger.log("邮件发送异常",e);
		}
	}


}
